
package saxParseXML;

/**
 * @作者 Administrator
 * @创建日期2015-3-14
 * @版本  用SAX解析XML的Handler
 */

/*用SAX解析XML采用的是从上而下的基于事件驱动的解析方式，在解析过程中会视情况自动调用
startDocument()、startElement()、characters()、endElement()、endDocument()等相关的方法。
startDocument()方法只会在文档开始解析的时候被调用，每次解析只会调用一次。
startElement()方法每次在开始解析一个元素，即遇到元素标签开始的时候都会调用。
characters()方法也是在每次解析到元素标签携带的内容时都会调用，即使该元素标签的内容为空或换行。
而且如果元素内嵌套元素，在父元素结束标签前， characters()方法会再次被调用，此处需要注意。
endElement()方法每次在结束解析一个元素，即遇到元素标签结束的时候都会调用。
endDocument() startDocument()方法只会在文档解析结束的时候被调用，每次解析只会调用一次。*/

 
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
 import org.xml.sax.helpers.DefaultHandler;
 
 public class SaxParseXml extends DefaultHandler {
     //存储正在解析的元素的数据
     private Map<String,String> map=null;
     //存储所有解析的元素的数据
     private List<Map<String,String>> list=null;
     //正在解析的元素的名字,即XML标签名
     String currentTag=null;
     //正在解析的元素的元素值
     String currentValue=null;
     //开始解析的元素,即xml节点元素
     String node=null;
     

     public SaxParseXml(String node) {
         // TODO Auto-generated constructor stub
         this.node=node;
    }    
     public List<Map<String, String>> getList() {
         return list;
     }
 
    
     @Override
     //开始解析文档，即开始解析XML根元素时调用该方法
     public void startDocument() throws SAXException {
        
         System.out.println("startDocument()开始解析XML文档--");
        //初始化Map
         list=new ArrayList<Map<String,String>>();
     }
     
    
     @Override 
   //开始解析每个元素时都会调用该方法
     
     /*qname 是qualified name 的简写.由构成：由名字空间(namespace)前缀(prefix)以及冒号(:),还有一个元素名称构成。如
      <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
          xmlns="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
          version="1.0">
       <xsl:template match="foo">
         <hr/>
       </xsl:template>
     </xsl:stylesheet>
     xsl是名字空间前缀，template是元素名称，xsl:template 就是一个qname;template就是localName;uri就是http://www.w3.org/1999/XSL/Transform
     qname无非是有着特定格式的xml元素，其作用主要是增加了名字空间，比如有同样的元素名称，而名字空间不同的情况*/
     public void startElement(String uri, String localName, String qName,Attributes attributes) throws SAXException {
         //判断正在解析的元素是不是开始解析的元素
         System.out.println("startElement()开始解析元素--"+qName);
         if(qName.equals(node)){
             map=new HashMap<String, String>();
         }
         
         //判断正在解析的元素是否有属性值,如果有则将其全部取出并保存到map对象中，如:<person id="00001"></person>
         if(attributes!=null&&map!=null){
             for(int i=0;i<attributes.getLength();i++){
                map.put(attributes.getQName(i), attributes.getValue(i));
             }
         }
         currentTag=qName;  //正在解析的元素
     }
     
     //解析到每个元素的内容时会调用此方法
     @Override
     public void characters(char[] ch, int start, int length)throws SAXException {
         System.out.println("characters()开始解析元素的文本值--");
         if(currentTag!=null&&map!=null){
             currentValue=new String(ch,start,length);
             //如果内容不为空和空格，也不是换行符则将该元素名和值和存入map中            
             if(currentValue!=null&&!currentValue.trim().equals("")&&!currentValue.trim().equals("\n"))
             {
                 map.put(currentTag, currentValue);
                 System.out.println("解析元素"+currentTag+"的文本值:"+currentValue);
             }
             //当前的元素已解析过，将其置空用于下一个元素的解析
             currentTag=null;            
             currentValue=null;
         }
     }
    
    
     @Override 
     //每个元素结束的时候都会调用该方法
     public void endElement(String uri, String localName, String qName) throws SAXException {
        
         System.out.println("endElement()结束解析元素--"+qName);
         //判断是否为一个节点结束的元素标签
         if(qName.equals(node)){
             list.add(map);
            map=null;
        }    
         
     }
     
    
     @Override
     //结束解析文档，即解析根元素结束标签时调用该方法
     public void endDocument() throws SAXException {
        
         System.out.println("endDocument()xml文档结束解析--");
         super.endDocument();
     }
 }
